package com.balabala.gym_consume.service.impl;

import com.balabala.api.UserFeignClient;
import com.balabala.gym_consume.pojo.dto.*;
import com.balabala.gym_consume.pojo.vo.*;
import com.balabala.result.Result;
import com.balabala.vo.User;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.balabala.api.ShippingAddressFeignClient;
import com.balabala.dto.UserInfoDto;
import com.balabala.exception.CustomerException;
import com.balabala.goods.api.CartFeignClient;
import com.balabala.goods.api.SkuFeignClient;
import com.balabala.goods.api.StockFeignClient;
import com.balabala.goods.pojo.Sku;
import com.balabala.goods.pojo.dto.CartItemDTO;
import com.balabala.goods.pojo.dto.LockStockDTO;
import com.balabala.gym_consume.constant.OrderConstant;
import com.balabala.gym_consume.pojo.entity.OrderDelivery;
import com.balabala.gym_consume.pojo.entity.OrderItem;
import com.balabala.gym_consume.service.OrderDeliveryService;
import com.balabala.gym_consume.service.OrderItemService;
import com.balabala.gym_consume.utils.MoneyUtil;
import com.balabala.gym_consume.utils.SnowFlake;
import com.balabala.gym_enum.ExceptionEnum;
import com.balabala.vo.ShippingAddressVo;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;

import com.baomidou.mybatisplus.core.enums.SqlMethod;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.balabala.gym_consume.mapper.OrderMapper;
import com.balabala.gym_consume.pojo.entity.Order;
import com.balabala.gym_consume.service.OrderService;

import org.apache.ibatis.binding.MapperMethod;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;

import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * (Order)表服务实现类
 *
 * @author 何涛
 * @since 2023-05-07 16:58:33
 */
@Service("orderService")
@Slf4j
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {
    @Autowired
    private UserFeignClient userFeignClient;

     @Autowired
    CartFeignClient cartFeignClient;
    @Autowired
    SkuFeignClient skuFeignClient;
    @Autowired
    ShippingAddressFeignClient shippingAddressFeignClient;

    @Autowired
    HttpServletRequest request;

    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    StockFeignClient stockFeignClient;

    @Autowired
    OrderItemService orderItemService;

    @Autowired
    OrderDeliveryService orderDeliveryService;

    @Override
    @Transactional(rollbackFor = {})
    public OrderConfirmVO confirm(OrderConfirmDTO orderConfirmDTO) {
        UserInfoDto userInfoDto = userFeignClient.getUserInfoByUserToken(request.getHeader("user-token")).getData();
        OrderConfirmVO orderConfirmVO=new OrderConfirmVO();
        List<OrderItemDTO> orderItemList = new ArrayList<>();
        if(orderConfirmDTO.getSkuId()==null){
            log.info("《==================================购物车订单==================================》");
            //获取购物车所有勾选的订单项
            List<CartItemDTO> cartItemDTOList = cartFeignClient.getUserCart().getData();
            //过滤出所有已勾选的商品,并放入对应的订单项
            List<OrderItemDTO> orderItemDTOList = cartItemDTOList.stream().filter(cartItemDTO -> cartItemDTO.getChecked()).map(cartItemDTO ->
                    OrderItemDTO.builder()
                            .skuId(cartItemDTO.getSkuId()).skuName(cartItemDTO.getSkuName())
                            .count(cartItemDTO.getCount()).price(cartItemDTO.getPrice())
                            .pic(cartItemDTO.getSkuPic()).skuCode(cartItemDTO.getSkuNo())
                            .spuId(cartItemDTO.getSpuId())
                            .categoryId(cartItemDTO.getCategoryId())
                            .categoryName(cartItemDTO.getCategoryName())
                            .spuName(cartItemDTO.getGoodsName()).build()).collect(Collectors.toList());
            orderItemList.addAll(orderItemDTOList);

        }
        else {
            log.info("《==================================直接购买==================================》");
            //根据sku id查询对应的sku 信息
            Sku sku = skuFeignClient.getSkuById(orderConfirmDTO.getSkuId()).getData();
            OrderItemDTO orderItemDTO = OrderItemDTO.builder()
                    .count(orderConfirmDTO.getCount()).skuId(orderConfirmDTO.getSkuId())
                    .skuName(sku.getSpuName()).skuCode(sku.getNo()).spuName(sku.getSpuName())
                    .price(MoneyUtil.fenToYuan(sku.getPrice() * orderConfirmDTO.getCount() ))
                    .pic(sku.getPicUrl())
                    .build();
            orderItemList.add(orderItemDTO);
        }

        //获取用户收货地址
        List<ShippingAddressVo> shippingAddressVoList = shippingAddressFeignClient.findUserAllShippingAddress(userInfoDto.getId()).getData();
        orderConfirmVO.setOrderItems(orderItemList);
        orderConfirmVO.setAddresses(shippingAddressVoList);
        //根据雪花算法生成一个orderToken防止重复提交
        String orderToken=SnowFlake.nextId()+"";
        orderConfirmVO.setOrderToken(orderToken);
        //保存订单token到redis中
        redisTemplate.boundValueOps(OrderConstant.PREFIX_ORDER_TOKEN+orderToken).set(orderToken);
        return orderConfirmVO;
    }

    @Override
    @Transactional(rollbackFor = {})
    public OrderSubmitVO submit(OrderSubmitDTO orderSubmitDTO) {
        UserInfoDto userInfoDto = userFeignClient.getUserInfoByUserToken(request.getHeader("user-token")).getData();
        log.info("《==================================提交订单==================================》");
        // 删除redis中的orderToken防止订单重复提交
        Boolean success = redisTemplate.boundValueOps(OrderConstant.PREFIX_ORDER_TOKEN + orderSubmitDTO.getOrderToken()).expire(-1, TimeUnit.SECONDS);
        if(!success){
            log.info("重复提交订单。。。");
            throw new CustomerException(ExceptionEnum.REPEAT_SUBMIT_ORDER);
        }
        log.info("《==================================删除redis中orderToken==================================》");
        // 订单验价
        Long nowTotalPrice = orderSubmitDTO.getOrderItems().stream().map(orderItemDTO -> skuFeignClient.getSkuById(orderItemDTO.getSkuId()).getData().getPrice() * orderItemDTO.getCount()).reduce(0L, Long::sum);

        if(!MoneyUtil.yuanToFen(orderSubmitDTO.getTotalPrice()).equals(nowTotalPrice)){
            log.info("商品价格有变动，请重新提交订单");
            throw new CustomerException(ExceptionEnum.PRICE_NOT_RIGHT);
        }
        log.info("《==================================验价成功==================================》");
        // 校验库存以及锁定库存
        //把所有订单项放入锁库存的传输对象中
        List<LockStockDTO> lockStockDTOS = orderSubmitDTO.getOrderItems().stream().map(orderItemDTO -> LockStockDTO.builder().isLock(false).orderToken(orderSubmitDTO.getOrderToken()).skuId(orderItemDTO.getSkuId()).count(orderItemDTO.getCount()).build()).collect(Collectors.toList());
        //进行批量库存锁定
        Result<String> lockResult = stockFeignClient.lock(lockStockDTOS);
        if(lockResult.getCode()!=0){
            log.info("库存不足：{}",lockResult.getData());
            throw new CustomerException(lockResult.getData(),lockResult.getCode());
        }
        log.info("《==================================库存锁定成功==================================》");
        int i=1/0;
        // 创建订单
        Order order = Order.builder()
                .sn(orderSubmitDTO.getOrderToken())
                .totalAmount(MoneyUtil.yuanToFen(orderSubmitDTO.getPayAmount()))
                .totalQuantity(orderSubmitDTO.getOrderItems().stream().map(orderItemDTO -> orderItemDTO.getCount()).reduce(0,Integer::sum))
                .sourceType(orderSubmitDTO.getSourceType())
                .status(OrderConstant.OrderStatus.WAIT_PAYMENT_STATUS)
                .remark(orderSubmitDTO.getRemark())
                .userId(userInfoDto.getId()).remark(orderSubmitDTO.getRemark())
                .payAmount(MoneyUtil.yuanToFen(orderSubmitDTO.getPayAmount()))
                .createTime(new Date())
                .updateTime(new Date())
                .timeout(new Date(System.currentTimeMillis()+OrderConstant.TIMEOUT))
                .build();

        save(order);
        log.info("《==================================订单已保存==================================》");
        // 创建订单项
        List<OrderItem> orderItems = orderSubmitDTO.getOrderItems().stream().map(orderItemDTO -> OrderItem.builder()
                .orderId(order.getId())
                .skuId(orderItemDTO.getSkuId())
                .skuNo(orderItemDTO.getSkuCode())
                .skuName(orderItemDTO.getSkuName())
                .skuPrice(MoneyUtil.yuanToFen(orderItemDTO.getPrice()))
                .skuCount(orderItemDTO.getCount())
                .skuTotalPrice(MoneyUtil.yuanToFen(orderItemDTO.getPrice())*orderItemDTO.getCount())
                .spuId(orderItemDTO.getSpuId())
                .spuName(orderItemDTO.getSpuName())
                .spuPic(orderItemDTO.getPic())
                .categoryId(orderItemDTO.getCategoryId())
                .categoryName(orderItemDTO.getCategoryName())
                .createTime(new Date())
                .updateTime(new Date())
                .build()).collect(Collectors.toList());
        //批量保存
        orderItemService.saveBatch(orderItems);
        log.info("《==================================订单项已保存==================================》");
        // 保存收货地址
        ShippingAddressVo deliveryAddress = orderSubmitDTO.getDeliveryAddress();
        orderDeliveryService.save(OrderDelivery.builder()
                        .orderId(order.getId())
                        .city(deliveryAddress.getAddress().split(":")[1])
                        .deliveryCompany("tt物流")
                        .deliverySn(UUID.randomUUID().toString())
                        .receiverName(deliveryAddress.getName())
                        .receiverPhone(deliveryAddress.getPhone())
                        .postCode(deliveryAddress.getCode())
                        .region(deliveryAddress.getAddress().split(":")[2])
                        .detailAddress(deliveryAddress.getAddress().split(":")[3])
                        .remark(orderSubmitDTO.getRemark())
                        .deliveryStatus(OrderConstant.OrderDeliverStatus.WAIT_SEND)
                        .createTime(new Date()).updateTime(new Date()).build());
        log.info("《==================================订单物流信息已保存==================================》");

//        //判断用户是否为直接购买
        if(orderSubmitDTO.getDirectBuy().equals(0)){
            // 删除购物车已勾选商品
            log.info("用户通过购物车购买,清空用户已选的购物项");
            cartFeignClient.deleteCartCheckSkus(orderSubmitDTO.getOrderItems().stream().map(orderItemDTO -> orderItemDTO.getSkuId()).collect(Collectors.toList()));
            log.info("《==================================已清除购物车勾选的购物项==================================》");
        }
        log.info("《==================================返回给前台订单id以及订单编号==================================》");
        return OrderSubmitVO.builder().orderId(order.getId()).orderSn(order.getSn()).build();

    }

    @Override
    public List<OrderQueryVo> findAllByLike(OrderServiceDto orderServiceDto) {
        //返回给前端的订单页的信息
        OrderQueryVo orderQueryVo = new OrderQueryVo();
       //接收返回信息
        List<OrderQueryVo> list = new ArrayList<>();

        List<OrderVo> orderVoList = getBaseMapper().findAllByLike(orderServiceDto);

            //远程调接口
//        BeanUtils.copyProperties(orderQueryVo, allByLike);
        for (int i = 0; i <orderVoList.size() ; i++) {
            Result<User> byId = userFeignClient.findById(orderVoList.get(i).getUserId());
            //设置订单页面信息
            orderQueryVo.setSn(orderVoList.get(i).getSn());
            orderQueryVo.setName(byId.getData().getName());
            orderQueryVo.setStatus(orderVoList.get(i).getStatus());
            orderQueryVo.setSourceType(orderVoList.get(i).getSourceType());
            orderQueryVo.setPayAmount(orderVoList.get(i).getPayAmount());
            list.add(orderQueryVo);
        }
        return list;
    }

    @Override
    public OrderBySnVoAddUserName findOrderBySn(String sn) {
         OrderBySnVo orderBySn = getBaseMapper().findOrderBySn(sn);
         OrderBySnVoAddUserName orderBySnVoAddUserName=new OrderBySnVoAddUserName();
         Result<User> user = userFeignClient.findById(orderBySn.getUserId());
         //把orderBySn里面的对得上orderBySnVoAddUserName中字段进行拷贝
         BeanUtils.copyProperties(orderBySn, orderBySnVoAddUserName);
         orderBySnVoAddUserName.setName(user.getData().getName());
         return orderBySnVoAddUserName;
    }

    @Override
    public GoodSnVo findGoodBySn(String sn) {
        return getBaseMapper().findGoodBySn(sn);
    }

    @Override
    public boolean updateOrderStatusByIds(UpdateOrderStatusDTO updateOrderStatusDTO) {
        return getBaseMapper().updateOrderStatusByIds(updateOrderStatusDTO.getIds());
    }


    @Override
    @Transactional
    public Boolean cancelOrderById(Long id) {
        log.info("《==================================订单取消==================================》");
        // 查询订单信息
        Order order = getById(id);

        // 是否为待支付状态，如果不是则订单取消失败
        if(order==null || order.getStatus().equals(OrderConstant.OrderStatus.WAIT_PAYMENT_STATUS)){
            log.info("订单状态不是待支付状态，不能取消");
            throw new CustomerException(ExceptionEnum.NO_PAYMENT_STATUS);
        }
        // 改变订单状态
        order.setStatus(OrderConstant.OrderStatus.USER_CANCEL_STATUS);
        updateById(order);
        // 释放锁库存
        return stockFeignClient.unLockStock(order.getSn());
    }

    @Override
    @Transactional
    public Boolean deleteOrderByOrderId(Long orderId) {
        log.info("《==================================订单删除==================================》");
        Order order = getById(orderId);
        if(order==null){
            log.info("订单不存在，无法删除！");
            throw new CustomerException(ExceptionEnum.NOT_HAS_ORDER);
        }
        if(!order.getStatus().equals(OrderConstant.OrderStatus.SYSTEM_CANCEL_STATUS)&&!order.getStatus().equals(OrderConstant.OrderStatus.USER_CANCEL_STATUS)){
            log.info("订单不处于取消状态，无法删除！");
            throw new CustomerException(ExceptionEnum.NOT_DELETE_ORDER);
        }
        //删除订单以及订单项以及物流信息

        return removeById(orderId)&&
                orderItemService.remove(new LambdaQueryWrapper<OrderItem>().eq(OrderItem::getOrderId,orderId))&&
                orderDeliveryService.remove(new LambdaQueryWrapper<OrderDelivery>().eq(OrderDelivery::getOrderId,orderId));
    }

    @Override
    public List<UserOrderPageItemDTO> orderList(OrderPageDTO orderPageDTO) {
        //todo 做es搜索

        List<UserOrderPageItemDTO> res=new ArrayList<>();
        if(orderPageDTO.getIsAll()){

            List<Order> orderList = list(new LambdaUpdateWrapper<Order>().eq(Order::getUserId, orderPageDTO.getUserId()));
            getUserOrderPageItemDtoList(res, orderList);
            log.info("查询全部订单");

        }else if(orderPageDTO.getRefund()){
            List<Order> orderList = list(new LambdaUpdateWrapper<Order>().eq(Order::getUserId, orderPageDTO.getUserId()).eq(Order::getStatus, OrderConstant.OrderStatus.REFUND_STATUS));
            getUserOrderPageItemDtoList(res,orderList);
            log.info("查询退款订单");
        }
        getUserOrderPageItemDtoList(res,list(new LambdaUpdateWrapper<Order>().eq(Order::getUserId,orderPageDTO.getUserId()).eq(Order::getSourceType,orderPageDTO.getSourceType())));
        if(StringUtils.isEmpty(orderPageDTO.getConditionName())){
            return res;
        }
        //根据订单号查询一下
        List<UserOrderPageItemDTO> snRes = res.stream().filter(userOrderPageItemDTO -> orderPageDTO.getConditionName().equals(userOrderPageItemDTO.getOrder().getSn())).collect(Collectors.toList());

        if(snRes.size()>0){
            return snRes;
        }
        res = res.stream().filter(userOrderPageItemDTO -> {

            List<OrderItem> orderItemList = userOrderPageItemDTO.getOrderItemList();
            List<String> spuNameList = orderItemList.stream().map(orderItem -> orderItem.getSpuName()).collect(Collectors.toList());
            return spuNameList.stream().filter(spuName -> spuName.contains(orderPageDTO.getConditionName())).collect(Collectors.toList()).size() > 0;
        }).collect(Collectors.toList());
        return res;
    }

    private void getUserOrderPageItemDtoList(List<UserOrderPageItemDTO> res, List<Order> orderList) {
        orderList.forEach(order -> {
            UserOrderPageItemDTO userOrderPageItemDTO = UserOrderPageItemDTO.builder().order(order).build();
            List<OrderItem> orderItemList = orderItemService.list(new LambdaUpdateWrapper<OrderItem>().eq(OrderItem::getOrderId, order.getId()));
            userOrderPageItemDTO.setOrderItemList(orderItemList);
            res.add(userOrderPageItemDTO);
        });
    }
}


